package org.chronologger.poppaea.client.widgets;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.ui.Widget;

public abstract class EventHandler {

	public static final EventHandler doNothing = new EventHandler() {
		public void fire(Event event) {
			event.stopPropagation();
			event.preventDefault();
		}
	};

	public static void setupMouseHandlers(final EventAware widget,
			final MouseEventHandler handler) {
		widget.addEventHandler(Event.MOUSEEVENTS, new EventHandler() {

			@Override
			public void fire(Event event) {
				switch (event.getTypeInt()) {
				case Event.ONMOUSEDOWN:
					handler.onMouseDown(event);
					break;
				case Event.ONMOUSEUP:
					handler.onMouseUp(event);
					break;
				case Event.ONMOUSEMOVE:
					handler.onMouseMove(event);
					break;
				case Event.ONMOUSEOVER:
					handler.onMouseOver(event);
					break;
				case Event.ONMOUSEOUT:
					handler.onMouseOut(event);
					break;
				}
			}

		});
	}

	public abstract void fire(Event event);

	private final static HashMap<EventAware, HashMap<Integer, Set<EventHandler>>> eventHandlers = new HashMap<EventAware, HashMap<Integer, Set<EventHandler>>>();

	protected static HashMap<Integer, Set<EventHandler>> getHandlers(
			EventAware widget) {
		HashMap<Integer, Set<EventHandler>> handlers;
		if (eventHandlers.containsKey(widget)) {
			handlers = eventHandlers.get(widget);
		} else {
			handlers = new HashMap<Integer, Set<EventHandler>>();
			eventHandlers.put(widget, handlers);
		}
		return handlers;
	}

	public static void addEventHandler(EventAware widget, int events,
			EventHandler handler) {
		HashMap<Integer, Set<EventHandler>> eventHandlers = getHandlers(widget);

		Set<EventHandler> handlers;

		((Widget) widget).sinkEvents(events);
		while (events != 0) {
			int nextBit = events ^ (events & (events - 1));
			events -= nextBit;
			if (!eventHandlers.containsKey(nextBit)) {
				handlers = new HashSet<EventHandler>();
				eventHandlers.put(nextBit, handlers);
			} else
				handlers = eventHandlers.get(nextBit);
			handlers.add(handler);
		}
	}

	public static void removeEventHandlers(EventAware widget, int events,
			EventHandler handler) {
		HashMap<Integer, Set<EventHandler>> eventHandlers = getHandlers(widget);
		while (events != 0) {
			int nextBit = events ^ (events & (events - 1));
			events -= nextBit;
			if (eventHandlers.containsKey(nextBit)) {
				Set<EventHandler> handlers = eventHandlers.get(nextBit);
				if (handlers.contains(handler))
					handlers.remove(handler);
				if (handlers.isEmpty())
					eventHandlers.remove(events);
			}
		}
	}

	public static void handleEvent(EventAware widget, Event event) {
		HashMap<Integer, Set<EventHandler>> eventHandlers = getHandlers(widget);
		Integer key = new Integer(event.getTypeInt());
		if (eventHandlers.containsKey(key)) {
			for (EventHandler h : eventHandlers.get(key)) {
				h.fire(event);
			}
		}
	}

}
